use std::borrow::Cow;
use tweeny_rpc::macros::service;

#[service(client)]
trait CoolServ {
    async fn proc1(&self, bytes: Cow<'static, [u8]>) -> usize;
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    use std::{str::FromStr, net::SocketAddr};
    use tokio::{io::AsyncReadExt, net::TcpStream};
    use tweeny_rpc::courier::codec::DefaultSerder;
    env_logger::init();
    let addr = SocketAddr::from_str("127.0.0.1:22331").unwrap();
    let (serving, handle) =
        CoolServClient::new(TcpStream::connect(addr).await.unwrap(), DefaultSerder);
    tokio::spawn(serving);

    let mut f =
        tokio::fs::File::open("/mnt/Data/Akira.1988.1080p.Bluray.AV1.Opus.Multi4-dAV1nci.mkv").await?;
    const BUF_SIZE: usize = 100 * 1024 * 1024;

    let mut buf = Box::new([0u8; BUF_SIZE]);
    let mut n = f.read(&mut *buf).await?;
    while n > 0 {
        let leaked: &'static mut _ = Box::leak(buf);
        let raw_ptr = leaked as *mut _;
        let res = handle.proc1(Cow::Borrowed(&leaked[..n]), None).await;
        println!("{res:?}");

        // SAFETY: the input to our rpc call is only read when serializing,
        // dropped when the serialization is done, so:
        // 0. the ptr isn't dangling since it's leaked from a Box
        // 1. the content is as valid as before the leak, so ptr[0..BUF_SIZE]
        //    is still valid and initialized.
        // 2. by the time the rpc call returns, no one else is holding the ptr
        buf = unsafe { Box::from_raw(raw_ptr) };
        n = f.read(&mut *buf).await?;
    }
    Ok(())
}
